2-4. 네트워크 계열

관통 질문: 개발 편의로 켠 소켓 옵션이 패킷 탈취 통로가 되지 않았는가?


17. 같은 포트번호의 다중 연결 CWE-605

신뢰 경계: SO_REUSEPORT + INADDR_ANY 바인딩 → UID 검증 없이 → 같은 포트를 공유하는 다른 프로세스 ⚠️ SO_REUSEADDR 보다 SO_REUSEPORT 가 실질적 위험이다. 같은 UID 로 도는 코드는 그 포트의 연결을 나눠 받을 수 있다.

공격 시나리오: 리눅스 TCP는 커널이 막지만(listen 중이면 bind 실패) UDP는 이 제한이 없다. SO_REUSEPORT 는 같은 주소·포트에 여러 소켓을 정식으로 허용하고 커널이 연결을 분배하므로, 같은 UID로 도는 다른 코드가 연결의 일부를 조용히 받아간다. 정상 서버가 계속 동작하기 때문에 탈취가 드러나지 않는다.

❌ Bad

int fd = socket(AF_INET, SOCK_STREAM, 0);
int on = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof on);
addr.sin_addr.s_addr = htonl(INADDR_ANY);          /* 모든 인터페이스 */
bind(fd, (struct sockaddr *)&addr, sizeof addr);
listen(fd, backlog);
/* 같은 UID 로 도는 다른 코드가 이 그룹에 낄 수 있다 */

✅ Good

inet_pton(AF_INET, "10.0.0.7", &addr.sin_addr);    /* 서비스할 인터페이스로 범위 축소 */
#ifdef USE_PORT_SHARDING
int on = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof on);   /* 부하 분산이 필요할 때만 */
#endif
bind(fd, (struct sockaddr *)&addr, sizeof addr);
listen(fd, backlog);
/* 켰다면 이 포트의 UID 가 곧 신뢰 경계 — 전용 계정으로 실행 */

치환 규칙: INADDR_ANY 대신 실제 서비스 인터페이스로 바인딩 범위 축소, SO_REUSEPORT 는 부하 분산이 실제 필요할 때만 켜고 전용 계정으로 격리. UDP 서버는 리눅스에서도 탈취가 성립하므로 수신 데이터 인증·무결성 검증을 별도로 둔다.


이 계열 미니 체크리스트

  • SO_REUSEADDR/SO_REUSEPORT 를 습관적으로(에러 회피용으로) 켜고 있지 않은가
  • INADDR_ANY 로 바인딩할 필요가 실제로 있는가, 특정 인터페이스로 좁힐 수 있는가
  • SO_REUSEPORT 를 쓰는 서비스 계정이 다른 프로세스와 공유되지 않는가
  • UDP 서버라면 수신 데이터의 인증·무결성 검증이 별도로 있는가

관련 노트